#include <crt_util.h>

static void do_work(void* arg)
{
    rc_return(arg != NULL);
    io_thread_t* p = (io_thread_t*)(arg);
    _threadpool_t* pool = (_threadpool_t*)(p->parent_context);

    if (pool->func.start) {
        pool->func.start(pool, p);
    }

    // Send Sem
    if (p->func.work) {
        _sem_post(&pool->sem);
        p->func.work(pool, p);
    }

    if (p->func.stop) {
        p->func.stop(pool, p);
        _sem_post(&pool->sem);
    }
}

static int thread_init(_threadpool_t* pool, io_thread_t* thread, void* ctx, int id)
{
    rc_error(thread != NULL && pool != NULL, S_ERROR);

    thread->ctx = ctx;
    thread->parent_context = pool;
    thread->func.start = pool->func.start;
    thread->func.work = pool->func.work;
    thread->func.stop = pool->func.stop;
    thread->func.error = pool->func.error;
    thread->id = id;

    return S_SUCCESS;
}
static int thread_start(io_thread_t* thread)
{
    rc_error(thread != NULL, S_ERROR);
    return _thread_create(&thread->threadhandler, do_work, thread);
}
static int thread_stop(io_thread_t* thread)
{
    rc_error(thread != NULL, S_ERROR);
    return _thread_join(&thread->threadhandler);
}

int start_threadpool(_threadpool_t* pool)
{
    unsigned long iloop = 0;
    rc_error(pool != NULL, S_ERROR);

    for (iloop = 0; iloop < pool->count; iloop++) {
        thread_start(pool->threads + iloop);
    }

    for (iloop = 0; iloop < pool->count; iloop++) {
        _sem_wait(&pool->sem);
    }

    _sem_wait(&pool->exit);

    return S_SUCCESS;
}
int stop_threadpool(_threadpool_t* pool)
{
    unsigned long iloop = 0;

    rc_error(pool != NULL, S_ERROR);
    // Create several threads to send signals several times, and wait for a few signals here
    for (iloop = 0; iloop < pool->count; iloop++) {
        _sem_wait(&pool->sem);
    }

    for (iloop = 0; iloop < pool->count; iloop++) {
        thread_stop(pool->threads + iloop);
    }

    _sem_post(&pool->exit);

    return S_SUCCESS;
}
int uinit_threadpool(_threadpool_t* pool)
{
    _sem_destroy(&pool->exit);

    _sem_destroy(&pool->sem);

    if (pool->threads)
        heap_free(pool->threads);

    return S_SUCCESS;
}

int init_threadpool(_threadpool_t* pool)
{
    unsigned int iloop = 0;

    rc_error(_sem_init(&pool->sem, 0) == 0, S_ERROR);

    rc_error(_sem_init(&pool->exit, 0) == 0, S_ERROR);

    pool->threads = (io_thread_t*)heap_malloc(pool->count * sizeof(io_thread_t));

    rc_error(pool != NULL, S_ERROR);

    for (iloop = 0; iloop < pool->count; iloop++) {
        thread_init(pool, pool->threads + iloop, pool->threads, iloop);
    }

    return S_SUCCESS;
}
